package top.milkbox.service;

import org.springframework.web.multipart.MultipartFile;
import top.milkbox.domain.User;
import com.baomidou.mybatisplus.extension.service.IService;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @author xiaoguo
 * @description 针对表【tb_user】的数据库操作Service
 * @createDate 2022-09-10 21:08:48
 */
public interface UserService extends IService<User> {

    /**
     * 预处理用户信息
     * 隐藏密码，拼接头像等
     *
     * @param user 未处理的user
     */
    void preprocessingUser(User user);

    /**
     * 通过邮箱查询这个用户的信息
     * 如果用户存在，将用户头像URL属性赋值
     *
     * @param email 邮箱地址
     * @return 如果存在则将用户数据返回，如果不存在则返回null
     */
    User getFromEmail(String email);

    /**
     * 用户注册，向数据库插入用户数据，自动生成用户名和用户昵称
     * 密码设为null，手机号设为null，头像设为默认名
     *
     * @param email 邮箱
     * @return 将注册好的用户信息返回，注册失败则返回null
     */
    User register(String email);

    /**
     * 保存用户头像
     * 1获取图片保存地址
     * 2保存图片
     * 3将头像地址保存到数据库
     * 4更新用户redis
     *
     * @param token  设备的token
     * @param avatar 头像文件
     * @return 保存成功返回true
     */
    Boolean saveUserAvatar(String token, MultipartFile avatar);

    /**
     * 重置用户头像
     * 1判断当前头像是否为默认头像
     * 2将非默认头像移动到弃用目录
     * 3修改数据库头像字段为默认头像
     * 4更新token信息
     *
     * @param token 设备的token
     * @return 成功返回true
     */
    Boolean resetUserAvatar(String token);

    /**
     * 修改用户昵称
     * 1通过token获取userid
     * 2通过id修改用户的昵称
     * 3更新token
     *
     * @param token        设备的token
     * @param userNickname 用户新昵称
     */
    Boolean changeUserNickname(String token, String userNickname);

    /**
     * 从redis缓存中获取用户的信息
     * 1通过token字符串查询redis，查看redis中是否有这一条数据，如果没有则证明当前设备未登录
     * 2如果有这一条数据，则从token字符串中截取出userId
     * 3通过userId查询redis，查询出用户对象的JSON字符串，如果没有则证明当前用户未登录
     * 4更新token中的时间戳
     * 5如果有则将JSON转换为user对象并返回
     *
     * @param token 设备的token
     * @return 返回null表示用户未登录，返回非空则用户已登录
     */
    User getUserFromRedis(String token);

    /**
     * 生成token字符串
     *
     * @param userId 用户主键
     * @return 返回token字符串
     */
    String generateToken(Integer userId);

    /**
     * 生成一个key，这个key是在redis中存放user的
     *
     * @param userId userID
     * @return String
     */
    String generateUserKey(String userId);

    /**
     * 设置用户信息到Redis缓存
     * <p>
     * 1抹去密码，拼接头像，或其他后续功能
     * <p>
     * 2从redis中查询所有以"t_用户Id_"为前缀的键，将这些键封装到map中，判断键的数量
     * <p>
     * 3如果map的数量小于2或者map中存在token这个键，则不需要下线任何设备。
     * 以token为键时间戳为值存入redis并设置其过期时间为7天，如果这个token已经存在于redis中
     * 则会自动覆盖旧的时间戳。
     * 然后以userId为键user对象的JSON字符串为值存入redis中并设置其过期时间为7天，
     * 如果redis中已经存在这个键，同样会覆盖，这样就会更新用户在redis中的信息。
     * <p>
     * 4（else）如果是其他情况，说明当前已经有2个设备登录了，又来了一个新的设备，这时就需要下线一个设备
     * 找出map中时间戳ascii码值最小的那个对应的键，即最早登录的设备的token
     * 然后将这个token从redis中删除，将新的token存入redis并设置其过期时间，
     * 然后以userId为键user对象的JSON字符串为值存入redis中并设置其过期时间为7天，
     * 如果redis中已经存在这个键，同样会覆盖，这样就会更新用户在redis中的信息。
     *
     * @param token 当前设备的token
     * @param user  要存入的user对象
     * @return 返回0表示设备过多有设备被挤退下线，返回1表示设备已经登录过了，
     * 返回2表示设备数量未达上线且当前设备还没有登录
     */
    int setUserToRedis(String token, User user);

    /**
     * 将token写入cookie，将cookie写入response
     *
     * @param token    token
     * @param response response
     */
    void setTokenToCookieToResponse(String token, HttpServletResponse response);

    /**
     * 让客户端删除cookie中的token
     * 创建一个新的token，存活时长为0，覆盖掉原来的就可以实现删除操作了
     *
     * @param response response
     */
    void removeTokenCookieFromResponse(HttpServletResponse response);

    /**
     * 移除当前用户的当前设备的redis中的信息
     * 只移除token对应的用户时间戳值，Redis中的user对象不受影响
     * 如果只有当前一个设备登录，则同时将user对象删除
     *
     * @param token 当前设备的token
     */
    void removeUserFromRedisForCurrentDevice(String token);

    /**
     * 移除当前用户的所有设备的redis中的信息
     * token和user信息全部都要删除
     *
     * @param token 当前设备的token
     */
    void removeUserFromRedisForAllDevice(String token);
}
